#include "instructions/constants/ldc.hpp"
#include "rtda/frame.h"
#include "rtda/heap/class.h"
#include "rtda/heap/string_pool.h"

#include <stdexcept>
#include <variant>

namespace jvm {
namespace instructions {

void Ldc::execute(std::shared_ptr<rtda::Frame> p_frame) {
    detail::ExecuteLdc(p_frame, _index);
}

void LdcW::execute(std::shared_ptr<rtda::Frame> p_frame) {
    detail::ExecuteLdc(p_frame, _index);
}

void Ldc2W::execute(std::shared_ptr<rtda::Frame> p_frame) {
    if (!p_frame) {
        throw std::runtime_error("Frame is null");
    }

    auto stack = p_frame->getOperandStack();
    if (!stack) {
        throw std::runtime_error("OperandStack is null");
    }

    auto cp = p_frame->getMethod()->getClass()->getConstantPool();
    auto constant = cp->getConstant(_index);

    if (constant.valueless_by_exception()) {
        throw std::runtime_error("Constant is in invalid state");
    }

    try {
        std::visit(
            [stack](auto&& arg) {
                using T = std::decay_t<decltype(arg)>;
                if constexpr (std::is_same_v<T, int64_t>) {
                    stack->pushLong(arg);
                }
                else if constexpr (std::is_same_v<T, double>) {
                    stack->pushDouble(arg);
                }
                else {
                    throw std::runtime_error(
                        "Ldc2W expected numeric constant, got: " +
                        std::string(typeid(T).name())
                    );
                }
            },
            constant
        );
    }
    catch (const std::bad_variant_access& e) {
        throw std::runtime_error("Variant access failed: " + std::string(e.what()));
    }
}

namespace detail {

void ExecuteLdc(std::shared_ptr<rtda::Frame> p_frame, uint16_t index) {
    auto stack = p_frame->getOperandStack();
    auto&& pclass = p_frame->getMethod()->getClass();
    auto cp = pclass->getConstantPool();
    auto constant = cp->getConstant(index);

    // 使用 std::visit 和 std::variant 处理不同类型
    std::visit(
        [stack, pclass](auto&& arg) {
            using T = std::decay_t<decltype(arg)>;
            if constexpr (std::is_same_v<T, int32_t>) {
                stack->pushInt(arg);
            } else if constexpr (std::is_same_v<T, float>) {
                stack->pushFloat(arg);
            }
            else if constexpr (std::is_same_v<T, std::string>) {
                auto internedStr = heap::StringPool::getInstance().JString(pclass->getLoder(), arg);
                stack->pushRef(internedStr);
            }
            else if constexpr (std::is_same_v<T, std::shared_ptr<heap::ClassRef>>) {
                auto classobj = arg->resolvedClass()->getJClass();
                stack->pushRef(classobj);
            }
            else {
                // TODO: 处理  MethodType, MethodHandle 等情况
                throw std::runtime_error("todo: ldc!");
            }
        },
        constant
    );
}

} // namespace detail

} // namespace instructions
} // namespace jvm